package com.zsj.juc.lock;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @author zsj
 * @version 1.0
 * @date 2024/4/19 20:33
 * @description 可重入锁(递归锁)
 */
public class ReentrantLockDemo {
    //可重入锁 值得是同一个线程在外层方法获取锁的时候
    //再次去获得这个锁 是不会被阻塞的 只要获取的锁对象是同一个 不会因为之前没有释放而被阻塞
    //可重入锁在一定程度上有效解决了 死锁的发生率


    public synchronized void m1() {
        System.out.println(Thread.currentThread().getName() + "come in");
        m2();
        System.out.println(Thread.currentThread().getName() + "end");
    }

    public synchronized void m2() {
        System.out.println(Thread.currentThread().getName() + "come in");
        m3();
        System.out.println(Thread.currentThread().getName() + "come end");
    }

    public synchronized void m3() {
        System.out.println(Thread.currentThread().getName() + "come in");
    }

    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();

        //方法也是一样的 因为同步方法 锁的是当前对象实例
        //可重入锁的原理 和普通锁的原理是一样的 因为ObjectMonitor
//        ReentrantLockDemo reentrantLockDemo = new ReentrantLockDemo();
//        new Thread(reentrantLockDemo::m1, "t1").start();


   /*     Object o = new Object();
        Object a = new Object();
        synchronized (o) {
            System.out.println(Thread.currentThread().getName());
            synchronized (a) {
                System.out.println(Thread.currentThread().getName());
                synchronized (o) {
                    System.out.println(Thread.currentThread().getName());
                    System.out.println("不会被阻塞");
                }
            }

        int a = ThreadLocalRandom.current().nextInt(3);
        lock.lock();
        if (a > 0) {
            System.out.println("再次加锁");
            lock.lock();
        }
        //再次加锁
        lock.lock();
        lock.unlock();
        lock.unlock();
        }*/


        //这里有一个非常重要的知识 你加了几次lock  在底层计数器也会增加几次
        //如果你的释放锁次数和你加锁的次数不对等 将会产生不同线程之间一起调用相同一把锁的思索问题
        //也就是最好在显示锁的情况下 你的加锁次数和解锁次数要匹配

        //演示上面注释的情况
        try {
            lock.lock();
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "come in");
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + "内层调用");
                    lock.lock();
                } finally {
                    //如果在这里少了一次解锁操作 那么t2线程会拿不到锁
                    lock.unlock();
                }
            }, "t1").start();
        } finally {
            lock.unlock();
        }

        new Thread(() -> {
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "come in");
            } finally {
                lock.unlock();
            }
        }, "t2").start();


        /**
         * 可重入锁分为 隐式锁 和 显式锁
         * 隐式锁就算synchronized修饰的锁
         * 显式锁就是类似ReentrantLock这样的可重入锁
         */

    }
}
